<!DOCTYPE HTML>
<html lang="en">
<head>
	<meta charset="UTF-8">
    <link media="all" rel="stylesheet" href="../css/common.css" type="text/css" />
    <script src="../js/jquery-1.6.2.min.js" type="text/javascript"></script>
    <script src="../js/prettify.js" type="text/javascript"></script>
    <script src="../js/plugin.js" type="text/javascript"></script>
    <script src="../js/garden.js" type="text/javascript"></script>
	<title>home</title>
    <script type="text/javascript">
        (function(){
            if(!/*@cc_on!@*/0)return;  
            var e = "abbr,article,aside,audio,bb,canvas,datagrid,datalist,details,dialog,eventsource,figure,footer,hgroup,header,mark,menu,meter,nav,output,progress,section,time,video".split(','),  
            i = 0,  
            length = e.length;  
            while( i < length ){  
                document.createElement(e[i++]);  
            }  
         })();
    </script>
</head>
<body class="home">
    <nav id="nav_main">
        <div class="topNav">
            <ul>
            	<li>
            		<a href="#">js</a>
            	</li>
            </ul>
            <a id="top" href="#" title="Back to top">top</a>
        </div>
    	<ul class="navContent">
            <li class="nav_object">
                <h1>
                	<a href="#object">对象</a>
                </h1>
                <ul>
                	<li>
                		<a href="#object.general">对象使用和属性</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                </ul>
            </li>
            <li class="nav_object active">
                <h1>
                	<a href="#object" class="active">对象</a>
                </h1>
                <ul>
                	<li>
                		<a href="#object.general">对象使用和属性</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                </ul>
            </li>
            <li class="nav_object">
                <h1>
                	<a href="#object">对象</a>
                </h1>
                <ul>
                	<li>
                		<a href="#object.general">对象使用和属性</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                </ul>
            </li>
            <li class="nav_object">
                <h1>
                	<a href="#object">对象</a>
                </h1>
                <ul>
                	<li>
                		<a href="#object.general">对象使用和属性</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                </ul>
            </li>
            <li class="nav_object">
                <h1>
                	<a href="#object">对象</a>
                </h1>
                <ul>
                	<li>
                		<a href="#object.general">对象使用和属性</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                </ul>
            </li>
            <li class="nav_object">
                <h1>
                	<a href="#object">对象</a>
                </h1>
                <ul>
                	<li>
                		<a href="#object.general">对象使用和属性</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                	<li>
                		<a href="#object.prototype">原型</a>
                	</li>
                </ul>
            </li>
    	</ul>
    </nav>
    <section id="object">
        <header id="object.intro">
        <h1>对象</h1>
        </header>
        <article id="object.general">
        <h2>﻿对象使用和属性</h2>
        <div>
            <p>JavaScript 中所有变量都是对象，除了两个例外 <a href="#core.undefined"><code>null</code></a> 和 <a href="#core.undefined"><code>undefined</code></a>。</p>
            <pre>
                <code>
                    <span class="kwd">false</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">()</span><span class="pln"> </span><span class="com">// 'false'</span><span class="pln"><br>
                    </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">].</span><span class="pln">toString</span><span class="pun">();</span><span class="pln"> </span><span class="com">// '1,2,3'</span>
                    <span class="pln"><br><br></span>
                    <span class="kwd">function</span><span class="pln"> </span><span class="typ">Foo</span><span class="pun">(){}</span><span class="pln"><br></span>
                    <span class="typ">Foo</span><span class="pun">.</span><span class="pln">bar </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"><br></span>
                    <span class="typ">Foo</span><span class="pun">.</span><span class="pln">bar</span><span class="pun">;</span><span class="pln"> </span><span class="com">// 1</span><span class="pln"><br></span>
                </code>
            </pre>
            <p>一个常见的误解是数字的字面值（literal）不是对象。这是因为 JavaScript 解析器的一个错误，它试图将<em>点操作符</em>解析为浮点数字面值的一部分。</p>
            <pre>
                <code>
                    <span class="lit">2.toString</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 出错：SyntaxError</span><span class="pln"><br></span>
                </code>
            </pre>
            <p>有很多变通方法可以让数字的字面值看起来像对象。</p>
            <pre>
                <code>
                    <span class="lit">2.</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 第二个点号可以正常解析</span><span class="pln"><br></span>
                    <span class="lit">2</span><span class="pln"> </span><span class="pun">.</span><span class="pln">toString</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 注意点号前面的空格</span><span class="pln"><br></span>
                    <span class="pun">(</span><span class="lit">2</span><span class="pun">).</span><span class="pln">toString</span><span class="pun">();</span><span class="pln"> </span><span class="com">// 2先被计算</span><span class="pln"><br></span>
                </code>
            </pre>
        </div>
        <div>
            <h3>对象作为数据类型</h3>
            <p>JavaScript 的对象可以作为<a href="http://en.wikipedia.org/wiki/Hashmap"><em>哈希表</em></a>使用，主要用来保存命名的键与值的对应关系。</p>
            <p>使用对象的字面语法 - <code>{}</code> - 可以创建一个简单对象。这个新创建的对象从 <code>Object.prototype</code>
            <a href="#object.prototype">继承</a>下面，没有任何<a href="#object.hasownproperty">自定义属性</a>。</p>
            <pre>
                <code>
                    <span class="kwd">var</span><span class="pln"> foo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span><span class="pln"> </span><span class="com">// 一个空对象</span><span class="pln"><br><br></span>
                    <span class="com">// 一个新对象，拥有一个值为12的自定义属性'test'</span><span class="pln"><br></span>
                    <span class="kwd">var</span><span class="pln"> bar </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">test</span><span class="pun">:</span><span class="pln"> </span><span class="lit">12</span><span class="pun">};</span><span class="pln"> <br></span>
                </code>
            </pre>
        </div>
        <div>
            <h3>访问属性</h3>
            <p>有两种方式来访问对象的属性，点操作符或者中括号操作符。</p>
            <pre>
                <code>
                    <span class="kwd">var</span><span class="pln"> foo </span><span class="pun">=</span><span class="pln"></span><span class="pun">{</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Kitten'</span><span class="pun">}</span><span class="pln"><br>foo</span><span class="pun">.</span><span class="pln">name</span><span class="pun">;</span><span class="pln"> </span><span class="com">// kitten</span><span class="pln"><br>foo</span><span class="pun">[</span><span class="str">'name'</span><span class="pun">];</span><span class="pln"> </span><span class="com">// kitten</span><span class="pln"><br><br></span><span class="kwd">var</span><span class="pln"> </span><span class="kwd">get</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'name'</span><span class="pun">;</span><span class="pln"><br>foo</span><span class="pun">[</span><span class="kwd">get</span><span class="pun">];</span><span class="pln"> </span><span class="com">// kitten</span><span class="pln"><br><br>foo</span><span class="pun">.</span><span class="lit">1234</span><span class="pun">;</span><span class="pln"> </span><span class="com">// SyntaxError</span><span class="pln"><br>foo</span><span class="pun">[</span><span class="str">'1234'</span><span class="pun">];</span><span class="pln"> </span><span class="com">// works</span><span class="pln"><br></span></code></pre>

    <p>两种语法是等价的，但是中括号操作符在下面两种情况下依然有效
    - 动态设置属性
    - 属性名不是一个有效的变量名（<strong><a href="http://cnblogs.com/sanshi/">译者注</a>：</strong>比如属性名中包含空格，或者属性名是 JS 的关键词）</p>

    <aside>
    <p><strong><a href="http://cnblogs.com/sanshi/">译者注</a>：</strong>在 <a href="http://www.jslint.com/">JSLint</a> 语法检测工具中，点操作符是推荐做法。</p>
    </aside>

    </div><div><h3>删除属性</h3>

    <p>删除属性的唯一方法是使用 <code>delete</code> 操作符；设置属性为 <code>undefined</code> 或者 <code>null</code> 并不能真正的删除属性，
    而<strong>仅仅</strong>是移除了属性和值的关联。</p>

<pre><code><span class="kwd">var</span><span class="pln"> obj </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; bar</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"><br>&nbsp; &nbsp; foo</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"><br>&nbsp; &nbsp; baz</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln"><br></span><span class="pun">};</span><span class="pln"><br>obj</span><span class="pun">.</span><span class="pln">bar </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pun">;</span><span class="pln"><br>obj</span><span class="pun">.</span><span class="pln">foo </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln"><br></span><span class="kwd">delete</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">baz</span><span class="pun">;</span><span class="pln"><br><br></span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">var</span><span class="pln"> i </span><span class="kwd">in</span><span class="pln"> obj</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">hasOwnProperty</span><span class="pun">(</span><span class="pln">i</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; &nbsp; &nbsp; console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> </span><span class="str">''</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> obj</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="pun">}</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br></span></code></pre>

    <p>上面的输出结果有 <code>bar undefined</code> 和 <code>foo null</code> - 只有 <code>baz</code> 被真正的删除了，所以从输出结果中消失。</p>

    </div><div><h3>属性名的语法</h3>

<pre><code><span class="kwd">var</span><span class="pln"> test </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="str">'case'</span><span class="pun">:</span><span class="pln"> </span><span class="str">'I am a keyword so I must be notated as a string'</span><span class="pun">,</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="kwd">delete</span><span class="pun">:</span><span class="pln"> </span><span class="str">'I am a keyword too so me'</span><span class="pln"> </span><span class="com">// 出错：SyntaxError</span><span class="pln"><br></span><span class="pun">};</span><span class="pln"><br></span></code></pre>

    <p>对象的属性名可以使用字符串或者普通字符声明。但是由于 JavaScript 解析器的另一个错误设计，
    上面的第二种声明方式在 ECMAScript 5 之前会抛出 <code>SyntaxError</code> 的错误。</p>

    <p>这个错误的原因是 <code>delete</code> 是 JavaScript 语言的一个<em>关键词</em>；因此为了在更低版本的 JavaScript 引擎下也能正常运行，
    必须使用<em>字符串字面值</em>声明方式。</p></div></article><article id="object.prototype"><h2>﻿原型</h2><div><p>JavaScript 不包含传统的类继承模型，而是使用 <em>prototypal</em> 原型模型。</p>

    <p>虽然这经常被当作是 JavaScript 的缺点被提及，其实基于原型的继承模型比传统的类继承还要强大。
    实现传统的类继承模型是很简单，但是实现 JavaScript 中的原型继承则要困难的多。
    (It is for example fairly trivial to build a classic model on top of it, while the
    other way around is a far more difficult task.)</p>

    <p>由于 JavaScript 是唯一一个被广泛使用的基于原型继承的语言，所以理解两种继承模式的差异是需要一定时间的。</p>

    <p>第一个不同之处在于 JavaScript 使用<em>原型链</em>的继承方式。</p>

    <aside>
    <p><strong>注意:</strong> 简单的使用 <code>Bar.prototype = Foo.prototype</code> 将会导致两个对象共享<strong>相同</strong>的原型。
    因此，改变任意一个对象的原型都会影响到另一个对象的原型，在大多数情况下这不是希望的结果。</p>
    </aside>

<pre><code><span class="kwd">function</span><span class="pln"> </span><span class="typ">Foo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">value </span><span class="pun">=</span><span class="pln"> </span><span class="lit">42</span><span class="pun">;</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br></span><span class="typ">Foo</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; method</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln"><br></span><span class="pun">};</span><span class="pln"><br><br></span><span class="kwd">function</span><span class="pln"> </span><span class="typ">Bar</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln"><br><br></span><span class="com">// 设置Bar的prototype属性为Foo的实例对象</span><span class="pln"><br></span><span class="typ">Bar</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Foo</span><span class="pun">();</span><span class="pln"><br></span><span class="typ">Bar</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">foo </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Hello World'</span><span class="pun">;</span><span class="pln"><br><br></span><span class="com">// 修正Bar.prototype.constructor为Bar本身</span><span class="pln"><br></span><span class="typ">Bar</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">constructor </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Bar</span><span class="pun">;</span><span class="pln"><br><br></span><span class="kwd">var</span><span class="pln"> test </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Bar</span><span class="pun">()</span><span class="pln"> </span><span class="com">// 创建Bar的一个新实例</span><span class="pln"><br><br></span><span class="com">// 原型链</span><span class="pln"><br>test </span><span class="pun">[</span><span class="typ">Bar</span><span class="pun">的实例]</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="typ">Bar</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">[</span><span class="typ">Foo</span><span class="pun">的实例]</span><span class="pln"> <br>&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="pun">{</span><span class="pln"> foo</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Hello World'</span><span class="pln"> </span><span class="pun">}</span><span class="pln"><br>&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="typ">Foo</span><span class="pun">.</span><span class="pln">prototype<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="pun">{</span><span class="pln">method</span><span class="pun">:</span><span class="pln"> </span><span class="pun">...};</span><span class="pln"><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">prototype<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="pun">{</span><span class="pln">toString</span><span class="pun">:</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="com">/* etc. */</span><span class="pun">};</span><span class="pln"><br></span></code></pre>

    <p>上面的例子中，<code>test</code> 对象从 <code>Bar.prototype</code> 和 <code>Foo.prototype</code> 继承下来；因此，
    它能访问 <code>Foo</code> 的原型方法 <code>method</code>。同时，它也能够访问<strong>那个</strong>定义在原型上的 <code>Foo</code> 实例属性 <code>value</code>。
    需要注意的是 <code>new Bar()</code> <strong>不会</strong>创造出一个新的 <code>Foo</code> 实例，而是
    重复使用它原型上的那个实例；因此，所有的 <code>Bar</code> 实例都会共享<strong>相同</strong>的 <code>value</code> 属性。</p>

    <aside>
    <p><strong>注意:</strong> <strong>不要</strong>使用 <code>Bar.prototype = Foo</code>，因为这不会执行 <code>Foo</code> 的原型，而是指向函数 <code>Foo</code>。
    因此原型链将会回溯到 <code>Function.prototype</code> 而不是 <code>Foo.prototype</code>，因此 <code>method</code> 将不会在 Bar 的原型链上。</p>
    </aside>

    </div><div><h3>属性查找</h3>

    <p>当查找一个对象的属性时，JavaScript 会<strong>向上</strong>遍历原型链，直到找到给定名称的属性为止。</p>

    <p>到查找到达原型链的顶部 - 也就是 <code>Object.prototype</code> - 但是仍然没有找到指定的属性，就会返回 <a href="#core.undefined">undefined</a>。</p>

    </div><div><h3>原型属性</h3>

    <p>当原型属性用来创建原型链时，可以把<strong>任何</strong>类型的值赋给它（prototype）。
    然而将原子类型赋给 prototype 的操作将会被忽略。</p>

<pre><code><span class="kwd">function</span><span class="pln"> </span><span class="typ">Foo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{}</span><span class="pln"><br></span><span class="typ">Foo</span><span class="pun">.</span><span class="pln">prototype </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> </span><span class="com">// 无效</span><span class="pln"><br></span></code></pre>

    <p>而将对象赋值给 prototype，正如上面的例子所示，将会动态的创建原型链。</p>

    </div><div><h3>性能</h3>

    <p>如果一个属性在原型链的上端，则对于查找时间将带来不利影响。特别的，试图获取一个不存在的属性将会遍历整个原型链。</p>

    <p>并且，当使用 <a href="#object.forinloop"><code>for in</code></a> 循环遍历对象的属性时，原型链上的<strong>所有</strong>属性都将被访问。</p>

    </div><div><h3>扩展内置类型的原型</h3>

    <p>一个错误特性被经常使用，那就是扩展 <code>Object.prototype</code> 或者其他内置类型的原型对象。</p>

    <p>这种技术被称之为 <a href="http://en.wikipedia.org/wiki/Monkey_patch">monkey patching</a> 并且会破坏<em>封装</em>。虽然它被广泛的应用到一些 JavaScript 类库中比如 <a href="http://prototypejs.org/">Prototype</a>,
    但是我仍然不认为为内置类型添加一些<em>非标准</em>的函数是个好主意。</p>

    <p>扩展内置类型的<strong>唯一</strong>理由是为了和新的 JavaScript 保持一致，比如 <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach"><code>Array.forEach</code></a>。</p>

    <aside>
    <p><strong><a href="http://cnblogs.com/sanshi/">译者注</a>：</strong>这是编程领域常用的一种方式，称之为 <a href="http://en.wikipedia.org/wiki/Backport">Backport</a>，也就是将新的补丁添加到老版本中。</p>
    </aside>

    </div><div><h3>总结</h3>

    <p>在写复杂的 JavaScript 应用之前，充分理解原型链继承的工作方式是每个 JavaScript 程序员<strong>必修</strong>的功课。
    要提防原型链过长带来的性能问题，并知道如何通过缩短原型链来提高性能。
    更进一步，绝对<strong>不要</strong>扩展内置类型的原型，除非是为了和新的 JavaScript 引擎兼容。</p></div></article><article id="object.hasownproperty"><h2>﻿<code>hasOwnProperty</code> 函数</h2><div><p>为了判断一个对象是否包含<em>自定义</em>属性而<em>不是</em><a href="#object.prototype">原型链</a>上的属性，
    我们需要使用继承自 <code>Object.prototype</code> 的 <code>hasOwnProperty</code> 方法。</p>

    <aside>
    <p><strong>注意:</strong> 通过判断一个属性是否 <code>undefined</code> 是<strong>不够</strong>的。
    因为一个属性可能确实存在，只不过它的值被设置为 <code>undefined</code>。</p>
    </aside>

    <p><code>hasOwnProperty</code> 是 JavaScript 中唯一一个处理属性但是<strong>不</strong>查找原型链的函数。</p>

<pre><code><span class="com">// 修改Object.prototype</span><span class="pln"><br></span><span class="typ">Object</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">bar </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> <br></span><span class="kwd">var</span><span class="pln"> foo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">goo</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pun">};</span><span class="pln"><br><br>foo</span><span class="pun">.</span><span class="pln">bar</span><span class="pun">;</span><span class="pln"> </span><span class="com">// 1</span><span class="pln"><br></span><span class="str">'bar'</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> foo</span><span class="pun">;</span><span class="pln"> </span><span class="com">// true</span><span class="pln"><br><br>foo</span><span class="pun">.</span><span class="pln">hasOwnProperty</span><span class="pun">(</span><span class="str">'bar'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// false</span><span class="pln"><br>foo</span><span class="pun">.</span><span class="pln">hasOwnProperty</span><span class="pun">(</span><span class="str">'goo'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln"><br></span></code></pre>

    <p>只有 <code>hasOwnProperty</code> 可以给出正确和期望的结果，这在遍历对象的属性时会很有用。
    <strong>没有</strong>其它方法可以用来排除原型链上的属性，而不是定义在对象<em>自身</em>上的属性。</p>

    </div><div><h3><code>hasOwnProperty</code> 作为属性</h3>

    <p>JavaScript <strong>不会</strong>保护 <code>hasOwnProperty</code> 被非法占用，因此如果一个对象碰巧存在这个属性，
    就需要使用<em>外部</em>的 <code>hasOwnProperty</code> 函数来获取正确的结果。</p>

<pre><code><span class="kwd">var</span><span class="pln"> foo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; hasOwnProperty</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="pun">},</span><span class="pln"><br>&nbsp; &nbsp; bar</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Here be dragons'</span><span class="pln"><br></span><span class="pun">};</span><span class="pln"><br><br>foo</span><span class="pun">.</span><span class="pln">hasOwnProperty</span><span class="pun">(</span><span class="str">'bar'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 总是返回 false</span><span class="pln"><br><br></span><span class="com">// 使用其它对象的 hasOwnProperty，并将其上下为设置为foo</span><span class="pln"><br></span><span class="pun">{}.</span><span class="pln">hasOwnProperty</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="pln">foo</span><span class="pun">,</span><span class="pln"> </span><span class="str">'bar'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// true</span><span class="pln"><br></span></code></pre>

    </div><div><h3>结论</h3>

    <p>当检查对象上某个属性是否存在时，<code>hasOwnProperty</code> 是<strong>唯一</strong>可用的方法。
    同时在使用 <a href="#object.forinloop"><code>for in</code> loop</a> 遍历对象时，推荐<strong>总是</strong>使用 <code>hasOwnProperty</code> 方法，
    这将会避免<a href="#object.prototype">原型</a>对象扩展带来的干扰。</p></div></article><article id="object.forinloop"><h2>﻿<code>for in</code> 循环</h2><div><p>和 <code>in</code> 操作符一样，<code>for in</code> 循环同样在查找对象属性时遍历原型链上的所有属性。</p>

    <aside>
    <p><strong>注意:</strong> <code>for in</code> 循环<strong>不会</strong>遍历那些 <code>enumerable</code> 设置为 <code>false</code> 的属性；比如数组的 <code>length</code> 属性。</p>
    </aside>

<pre><code><span class="com">// 修改 Object.prototype</span><span class="pln"><br></span><span class="typ">Object</span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">bar </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"><br><br></span><span class="kwd">var</span><span class="pln"> foo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">moo</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">};</span><span class="pln"><br></span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">var</span><span class="pln"> i </span><span class="kwd">in</span><span class="pln"> foo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln"> </span><span class="com">// 输出两个属性：bar 和 moo</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br></span></code></pre>

    <p>由于不可能改变 <code>for in</code> 自身的行为，因此有必要过滤出那些不希望出现在循环体中的属性，
    这可以通过 <code>Object.prototype</code> 原型上的 <a href="#object.hasownproperty"><code>hasOwnProperty</code></a> 函数来完成。</p>

    <aside>
    <p><strong>注意:</strong> 由于 <code>for in</code> 总是要遍历整个原型链，因此如果一个对象的继承层次太深的话会影响性能。</p>
    </aside>

    </div><div><h3>使用 <code>hasOwnProperty</code> 过滤</h3>

<pre><code><span class="com">// foo 变量是上例中的</span><span class="pln"><br></span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">var</span><span class="pln"> i </span><span class="kwd">in</span><span class="pln"> foo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">foo</span><span class="pun">.</span><span class="pln">hasOwnProperty</span><span class="pun">(</span><span class="pln">i</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln"><br>&nbsp; &nbsp; &nbsp; &nbsp; console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln"><br>&nbsp; &nbsp; </span><span class="pun">}</span><span class="pln"><br></span><span class="pun">}</span><span class="pln"><br></span></code></pre>

    <p>这个版本的代码是唯一正确的写法。由于我们使用了 <code>hasOwnProperty</code>，所以这次<strong>只</strong>输出 <code>moo</code>。
    如果不使用 <code>hasOwnProperty</code>，则这段代码在原生对象原型（比如 <code>Object.prototype</code>）被扩展时可能会出错。</p>

    <p>一个广泛使用的类库 <a href="http://www.prototypejs.org/">Prototype</a> 就扩展了原生的 JavaScript 对象。
    因此，但这个类库被包含在页面中时，不使用 <code>hasOwnProperty</code> 过滤的 <code>for in</code> 循环难免会出问题。</p>

    </div><div><h3>总结</h3>

    <p>推荐<strong>总是</strong>使用 <code>hasOwnProperty</code>。不要对代码运行的环境做任何假设，不要假设原生对象是否已经被扩展了。</p></div></article></section>

</body>
</html>
